﻿using OpenCvSharp;
using Size = OpenCvSharp.Size;

public static class NoiseCleaner
{
    /// <summary>
    /// 清理黑底白字图像中的白色噪点
    /// </summary>
    /// <param name="src">输入图像（黑底白字）</param>
    /// <param name="noiseMaxSize">最大噪点尺寸（面积小于此值的白色区域将被清除）</param>
    /// <param name="kernelSize">形态学操作核大小（奇数）</param>
    /// <returns>清理后的图像</returns>
    public static Mat CleanWhiteNoise(Mat src, int noiseMaxSize = 10, int kernelSize = 3)
    {
        // 转换为灰度图（如果原是彩色图）
        using var gray = src.Channels() == 3 ?
            src.CvtColor(ColorConversionCodes.BGR2GRAY) :
            src.Clone();

        // 二值化（确保白字黑底）
        using var binary = new Mat();
        Cv2.Threshold(gray, binary, 0, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary);

        // 方法1：通过面积过滤（推荐）
        using var cleaned = new Mat();
        CleanByArea(binary, cleaned, noiseMaxSize, kernelSize);

        return cleaned;

        /* 方法2：纯形态学处理（速度更快但精度稍低）
        using var kernel = Cv2.GetStructuringElement(
            MorphShapes.Ellipse, 
            new Size(kernelSize, kernelSize));
        
        // 先开运算去除小噪点，再闭运算连接断裂文字
        binary.MorphologyEx(cleaned, MorphTypes.Open, kernel, iterations: 1);
        cleaned.MorphologyEx(cleaned, MorphTypes.Close, kernel, iterations: 1);
        return cleaned;
        */
    }

    private static void CleanByArea(Mat binary, Mat output, int maxNoiseSize, int kernelSize)
    {
        // 查找所有连通域
        using var labels = new Mat();
        using var stats = new Mat();
        using var centroids = new Mat();
        int numLabels = Cv2.ConnectedComponentsWithStats(binary, labels, stats, centroids);

        // 创建输出图像（全黑背景）
        output.SetTo(Scalar.Black);

        // 遍历所有连通域（跳过背景标签0）
        for (int i = 1; i < numLabels; i++)
        {
            int area = stats.At<int>(i, (int)ConnectedComponentsTypes.Area);

            // 保留大面积区域（文字部分）
            if (area > maxNoiseSize)
            {
                // 提取当前连通域的矩形区域
                int x = stats.At<int>(i, (int)ConnectedComponentsTypes.Left);
                int y = stats.At<int>(i, (int)ConnectedComponentsTypes.Top);
                int width = stats.At<int>(i, (int)ConnectedComponentsTypes.Width);
                int height = stats.At<int>(i, (int)ConnectedComponentsTypes.Height);
                var roi = new Rect(x, y, width, height);

                // 在原二值图中提取该区域
                using var component = new Mat(binary, roi);

                // 在输出图像的对应位置绘制保留的区域
                using var dstRoi = new Mat(output, roi);
                component.CopyTo(dstRoi);
            }
        }

        //// 可选：用形态学操作修复文字笔画
        //if (kernelSize > 0)
        //{
        //    using var kernel = Cv2.GetStructuringElement(
        //        MorphShapes.Ellipse,
        //        new Size(kernelSize, kernelSize));
        //    output.MorphologyEx(output, MorphTypes.Close, kernel);
        //}
    }
}